import { useClipboard } from '@/hooks';

const { setClipboardData } = useClipboard();

/**
 * 判断是否在微信浏览器内
 * @return {boolean}
 */
export const isWechat = (): boolean => {
  return navigator.userAgent.toLowerCase().includes('micromessenger');
};

export const closePage = () => {
  // 如果不是在微信环境，直接使用 window.close()
  if (!isWechat()) {
    window.close();
    return;
  }

  // 微信环境下的处理
  const doClose = () => {
    // 通过 window 对象访问 WeixinJSBridge，避免作用域和重复声明问题
    const bridge = (window as any).WeixinJSBridge;
    if (bridge && typeof bridge.call === 'function') {
      // 使用 call 方法关闭窗口
      bridge.call('closeWindow');
    }
    else {
      // 降级处理或记录日志
      console.warn('WeixinJSBridge not available or not ready, cannot close window via WeChat JSBridge.');
      // window.history.back(); // 可选的降级方案
    }
  };

  // 对于 iOS WKWebView 或某些情况，WeixinJSBridge 可能需要事件触发后才可用
  // 注意：这里直接访问 window.WeixinJSBridge
  if (!(window as any).WeixinJSBridge) {
    document.addEventListener(
      'WeixinJSBridgeReady',
      () => {
        doClose();
      },
      false,
    );
  }

  // 对于 Android 或者 WeixinJSBridge 已经加载好的情况，直接尝试调用
  // 使用 setTimeout 确保事件监听器先注册（如果需要的话）
  setTimeout(() => {
    doClose();
  }, 0); // 0ms 延迟通常足够
};

/**
 * h5中打开App
 * @description 如果没下载app，android:直接下载、ios:跳转到AppStore。如果已下载，则直接打开
 * @param scheme urlscheme
 * @param downloadUrl app的下载地址 如果打开的是ios:传入AppStore的下载地址，android:传入apk的下载地址
 * @param h5Url h5中的app下载页的地址
 */
export const openApp = (scheme: string = 'weixin://', downloadUrl: string = '', h5Url?: string) => {
  if (isWechat()) {
    // 在微信环境内可以使用微信开放标签wx-open-launch-app直接打开app 这样体验更好
    return uni.showModal({
      title: '温馨提示',
      content: '请在浏览器中打开该网页',
      confirmText: '复制链接',
      showCancel: false,
      success() {
        if (h5Url) setClipboardData({ data: h5Url });
      },
    });
  }

  uni.showLoading({
    title: '加载中',
  });
  const currentTime = Date.now();
  window.location.href = scheme;

  // 启动间隔20ms运行的定时器，并检测累计消耗时间是否超过3000ms，超过则结束
  let count = 0;
  let timer: number | undefined;
  timer = setInterval(() => {
    count++;
    const endTime = Date.now() - currentTime;
    if (count >= 100 || endTime > 3000) {
      uni.hideLoading();
      clearInterval(timer);
      timer = undefined;
      const hidden = window.document.hidden;
      if (typeof hidden === 'undefined' || hidden === false) {
        if (downloadUrl) window.location.href = downloadUrl;
      }
    }
  }, 20);
};

/**
 * @description 取一个区间数
 * @param {number} min 最小值
 * @param {number} max 最大值
 */
export function random(min: number, max: number) {
  if (min >= 0 && max > 0 && max >= min) {
    const gab = max - min + 1;
    return Math.floor(Math.random() * gab + min);
  }
  return 0;
}

/**
 * @description 格式化时间
 * @param {string | number} dateTime 需要格式化的时间戳
 * @param {string} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
 * @returns {string} 返回格式化后的字符串
 */
export function timeFormat(dateTime: string | number, formatStr = 'yyyy-mm-dd') {
  let date: Date;
  // 若传入时间为假值，则取当前时间
  if (!dateTime) {
    date = new Date();
  }
  // 若为unix秒时间戳，则转为毫秒时间戳（逻辑有点奇怪，但不敢改，以保证历史兼容）
  else if (typeof dateTime === 'number' && /^\d{10}$/.test(String(dateTime))) {
    date = new Date(dateTime * 1000);
  }
  // 若用户传入字符串格式时间戳，new Date无法解析，需做兼容
  else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime)) {
    date = new Date(Number(dateTime));
  }
  // 其他都认为符合 RFC 2822 规范
  else {
    // 处理平台性差异，在Safari/Webkit中，new Date仅支持/作为分割符的字符串时间
    date = new Date(
      typeof dateTime === 'string' && dateTime
        ? (dateTime as string).replace(/-/g, '/')
        : dateTime,
    );
  }

  const timeSource = {
    y: date.getFullYear().toString(), // 年
    m: (date.getMonth() + 1).toString().padStart(2, '0'), // 月
    d: date.getDate().toString().padStart(2, '0'), // 日
    h: date.getHours().toString().padStart(2, '0'), // 时
    M: date.getMinutes().toString().padStart(2, '0'), // 分
    s: date.getSeconds().toString().padStart(2, '0'), // 秒
    // 有其他格式化字符需求可以继续添加，必须转化成字符串
  };

  for (const key in timeSource) {
    const [ret] = new RegExp(`${key}+`).exec(formatStr) || [];
    if (ret) {
      // 年可能只需展示两位
      const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0;
      formatStr = formatStr.replace(ret, timeSource[key as keyof typeof timeSource].slice(beginIndex));
    }
  }

  return formatStr;
}

/**
 * 下载文件资源到本地
 * @param url 下载资源的 url
 * @param header HTTP 请求 Header, header 中不能设置 Referer
 * @param filePath 指定文件下载后存储的路径 (本地路径)
 * @return 返回文件的本地临时路径
 */
export const downloadFile = (url: string, header: Record<string, string> = {}, filePath?: string): Promise<string> => {
  return new Promise((resolve, reject) => {
    uni.downloadFile({
      url,
      header,
      filePath,
      success: (res) => {
        if (res.statusCode === 200) {
          resolve(res.tempFilePath);
        }
        else {
          if (res.errMsg) uni.showToast({ title: res.errMsg, icon: 'none' });
          reject(new Error(res.errMsg));
        }
      },
      fail: (err) => {
        uni.showToast({ title: '下载文件失败', icon: 'none' });
        reject(new Error(err));
      },
    });
  });
};

/**
 * 保存图片到手机
 * @param url 图片的路径，可以是相对路径，临时文件路径，存储文件路径，网络图片路径
 */
export const saveImageToPhotosAlbum = (url: string): Promise<void> => {
  return new Promise((resolve, reject) => {
    // 在uniapp环境中打开的webview的h5网页，可以使用plus对象
    if (navigator.userAgent.includes('uni-app')) {
      plus.gallery.save(url, () => {
        uni.showToast({
          title: '保存成功',
          icon: 'success',
        });
        resolve();
      }, () => {
        uni.showToast({ title: '保存失败', icon: 'none' });
        reject(new Error('保存失败'));
      });
    }
    else {
      downloadFile(url)
        .then((filePath) => {
          const oA = document.createElement('a');
          oA.download = '';
          oA.href = filePath;
          document.body.appendChild(oA);
          oA.click();
          oA.remove();
          uni.showToast({
            title: '保存成功',
            icon: 'success',
          });
          resolve();
        })
        .catch(() => {
          reject(new Error('保存失败'));
        });
    }
  });
};
